package com.huihang.core.utils;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.List;
import java.util.stream.IntStream;

/**
 * 身份证校准工具
 */
public class IdCardCalibrationUtil {
    private static final List<Integer> FACTORS = List.of(7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2);
    private static final String[] VERIFY_CODES = {"1", "0", "X", "9", "8", "7", "6", "5", "4", "3", "2"};
    private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMdd");

    public static boolean validateIdCard(String idCard) {
        return switch (idCard.length()) {
            case 18 -> validate18DigitIdCard(idCard);
            case 15 -> validateConverted15DigitIdCard(idCard);
            default -> false;
        };
    }

    private static boolean validate18DigitIdCard(String idCard) {
        var sum = IntStream.range(0, 17)
                .map(i -> Character.getNumericValue(idCard.charAt(i)) * FACTORS.get(i))
                .sum();
        var mod = sum % 11;
        return VERIFY_CODES[mod].equalsIgnoreCase(idCard.substring(17));
    }

    private static boolean validateConverted15DigitIdCard(String idCard) {
        if (!idCard.matches("\\d{15}")) {
            return false;
        }
        try {
            String newBirthDate = "19" + idCard.substring(6, 8) + idCard.substring(6, 12);
            LocalDate.parse(newBirthDate, DATE_FORMATTER);

            String newIdCard = idCard.substring(0, 6) + newBirthDate + idCard.substring(12, 15);
            String checkSum = calculateCheckSum(newIdCard);

            return validate18DigitIdCard(newIdCard + checkSum);
        } catch (DateTimeParseException e) {
            return false;
        }
    }

    private static String calculateCheckSum(String idCard) {
        var sum = IntStream.range(0, 17)
                .map(i -> Character.getNumericValue(idCard.charAt(i)) * FACTORS.get(i))
                .sum();
        int mod = sum % 11;
        return VERIFY_CODES[mod];
    }
}
